// 基于 Web Audio API 实现音频可视化效果
const audioFile = document.querySelector("audio");
const cvs = document.querySelector("canvas");
const ctx = cvs.getContext("2d");

function initCvs() {
  cvs.width = window.innerWidth * devicePixelRatio;
  cvs.height = (window.innerHeight / 2) * devicePixelRatio;
}
initCvs();

let isInit = false;
let isEnd = true
let analyser = null;
let buffer = null;
function initAudio() {
  // 创建音屏上下文
  const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
  // 创建音频分析器节点
  analyser = audioCtx.createAnalyser();
  // 创建音频源
  const source = audioCtx.createMediaElementSource(audioFile);
  // const source = audioCtx.createMediaStreamSource(stream);
  // 音频源 -> 分析器节点 -> 输出设备
  // 音频源与音频分析器建立连接
  source.connect(analyser);
  // 使用FFT时域图转频域图（频域转换）
  // 分析器节点 (Analyser Node) 将在一个特定的频率域里使用快速傅立叶变换(Fast Fourier Transform (FFT) ) 来捕获音频数据，
  // 这取决于你给 AnalyserNode.fftSize 属性赋的值（如果没有赋值，默认值为 2048）。
  // fftSize值越大，分析的越精细，性能消耗越高，这个值只能是2的n次方
  analyser.fftSize = 512;
  // 它是 FFT 的一半
  const bufferLength = analyser.frequencyBinCount;
  // 类型化数组
  // 把 frequencyBinCount 作为它的长度参数——这代表我们将对这个尺寸的 FFT 收集多少数据点。
  buffer = new Uint8Array(bufferLength);
  // 音频源与输出设备建立连接,audioCtx.distortion就是当前使用的输出设备
  // 分析器节点 (Analyser Node) 不一定输出到另一个节点，不输出时也可以正常使用。但前提是它必须与一个声源相连（直接或者通过其他节点间接相连都可以）。
  analyser.connect(audioCtx.destination);
  isInit = true;
}
audioFile.addEventListener("play", () => {
  console.log('play')
  if (isInit) return;
  isEnd = false
  initAudio();
});

audioFile.addEventListener("ended", () => {
  console.log('isend==========================================')
  isEnd = true
});

function draw() {
  requestAnimationFrame(draw);
  if (!isInit && isEnd) return;
  const { width, height } = cvs;
  ctx.clearRect(0, 0, width, height);
  ctx.fillStyle = "rgb(200, 200, 200)";
  // analyser.getByteFrequencyData得到字节类型的频域数据并赋值给buffer
  analyser.getByteFrequencyData(buffer);
  console.log(buffer)
  // 有些数据没有声音，所以截取一部分声音源
  const bufferLength = buffer.length / 2.5;
  // 为了好看绘制2份做镜像
  const count = bufferLength * 2;
  const barWidth = width / count;
  for (let i = 0; i < bufferLength; i++) {
    const v = buffer[i];
    // v的最大值为255，算出比例乘以绘制区域的高度
    const barHeight = (v / 255) * height;
    // 右边的镜像
    const x = barWidth * i + width / 2;
    // 左边的镜像
    const x2 = width / 2 - (i + 1) * barWidth;
    const y = height - barHeight;
    ctx.fillRect(x, y, barWidth - 2, barHeight);
    ctx.fillRect(x2, y, barWidth - 2, barHeight);
  }
}

draw()
